﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../global/head.h"
#include "../xos/head.h"
#include "../misc/head.h"
#include "file_impl.h"
#include "dir_impl.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static dir_impl::POOL * pool_ptr = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //

    dir_impl::dir_impl()
    {}

    dir_impl::~dir_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int dir_impl::get_addr( POOL *** pppPool, LIST *** pppList )
    {
        int ret = 0;
        if( pppPool )
        {
            *pppPool = &pool_ptr;
        }
        if( pppList )
        {
            *pppList = 0;
        }
        return ret;
    }

    int dir_impl::init()
    {
        int nRet = 0;
        return nRet;
    }

    int dir_impl::term()
    {
        int nRet = 0;
        clear_list( m_file_list );
        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int dir_impl::clear_list( FILE_LIST & file_list )
    {
        int nRet = 0;

        for( FILE_ITER iter = file_list.begin(); iter != file_list.end(); ++iter )
        {
            file_impl * p = *iter;
            p->release();
        }

        file_list.clear();
        m_file_iter = file_list.end();

        return nRet;
    }

    //////////////////////////////////////////////////////////////////////////////////
    // 
    // get full file name path
    // 

    int dir_impl::get_file_path( char * lpszPath, int nLen, const char * lpszFile )
    {
        int nRet = 0;

        const char * p = 0;
        int len = 0;

        if( 0 == nRet )
        {
            if( !lpszPath || ( 0 == strlen( lpszPath ) ) || !lpszFile || ( 0 == strlen( lpszFile ) ) )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            p = strrchr( lpszFile, '/' );

            if( !p )
            {
                nRet = 1;
            }
            else
            {
                len = p - lpszFile;
            }
        }

        if( 0 == nRet )
        {
            if( nLen <= len )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            strncpy( lpszPath, lpszFile, len );
        }

        return nRet;
    }

    // 
    // create dir and sub dirs
    // 
    int dir_impl::create_directory( const char * lpszPath )
    {
        using namespace std;

        int nRet = 0;

        nRet = mkdir( lpszPath, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH );

        if( -1 == nRet )
        {
            if( 17 != errno )
            {
            }
            else
            {
                nRet = 0;
            }
        }
        else
        {
            nRet = 0;
        }

        return nRet;
    }

    // 
    // delete dir and sub dirs
    // 
    int dir_impl::delete_directory( const char * lpszPath )
    {
        int nRet = 0;

        struct dirent * ent = 0;
        DIR * pDir = 0;
        char file[4096] = { 0 };
        struct stat st = { 0 };
        i_misc * pMisc = 0;

        g_pXos->create( xos::i_xos::XOS_OBJ_MISC, ( void ** )&pMisc );
        pDir = opendir( lpszPath );

        while( pDir && ( ent = readdir( pDir ) ) )
        {
            strcpy( file, lpszPath );
            pMisc->path_append( file, ent->d_name );
            lstat( file, &st );

            if( S_ISDIR( st.st_mode ) )
            {
                if( ( 0 != strcmp( ent->d_name, "." ) ) && ( 0 != strcmp( ent->d_name, ".." ) ) )
                {
                    delete_directory( file );
                }
            }
            else
            {
                delete_file( file );
            }
        }

        if( pDir )
        {
            closedir( pDir );
            pDir = 0;
        }

        xos_stl::release_interface( pMisc );
        remove( lpszPath );

        return nRet;
    }

    // 
    // if a dir exists
    // 
    int dir_impl::is_dir_exist( const char * lpszPath )
    {
        int ret = 0;

        struct stat buf = { 0 };

        if( 0 == ret )
        {
            int r = stat( lpszPath, &buf );
            if( -1 == r )
            {
                ret = 1;
            }
        }

        // S_ISDIR来判断是否为目录
        // if is file - S_ISREG
        if( ( 0 == ret ) && !S_ISDIR( buf.st_mode ) )
        {
            ret = 1;
        }

        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////
    // 
    /// clear last result and find with lpszPath filter
    // 
    int dir_impl::begin_find_file( const char * lpszPath )
    {
        int nRet = 0;

        clear_list( m_file_list );

        struct dirent * ent = 0;
        DIR * pDir = 0;
        char file[4096] = { 0 };
        struct stat st = { 0 };
        i_misc * pMisc = 0;

        g_pXos->create( xos::i_xos::XOS_OBJ_MISC, ( void ** )&pMisc );
        pDir = opendir( lpszPath );

        while( pDir && ( ent = readdir( pDir ) ) )
        {
            strcpy( file, lpszPath );
            pMisc->path_append( file, ent->d_name );
            lstat( file, &st );

            i_file::enumFileType enumType = i_file::FILE_TYPE_NONE;

            if( S_ISDIR( st.st_mode ) )
            {
                if( ( 0 != strcmp( ent->d_name, "." ) ) && ( 0 != strcmp( ent->d_name, ".." ) ) )
                {
                    enumType = i_file::FILE_TYPE_DIR;
                }
                else
                {
                    enumType = i_file::FILE_TYPE_NONE;
                }
            }
            else
            {
                enumType = i_file::FILE_TYPE_FILE;
            }

            if( i_file::FILE_TYPE_NONE != enumType )
            {
                file_impl * p = 0;
                void * pp = 0;

                g_pXos->create( i_xos::XOS_OBJ_FILE, ( void ** )&pp );

                if( pp )
                {
                    p = ( file_impl * )pp;
                    strcpy( p->m_szFileName, ent->d_name );
                    p->m_enumType = enumType;
                    m_file_list.push_back( p );
                }
            }
        }

        if( pDir )
        {
            closedir( pDir );
            pDir = 0;
        }

        xos_stl::release_interface( pMisc );
        m_file_iter = m_file_list.begin();

        return nRet;
    }

    // 
    // finish find with filter
    // 
    int dir_impl::end_find_file()
    {
        int nRet = 0;

        // 
        // clear
        // 
        clear_list( m_file_list );

        return nRet;
    }

    // 
    // get find results one by one. null means to the end
    // 
    int dir_impl::get_find_result( i_file ** ppFile )
    {
        int nRet = 0;

        if( m_file_iter != m_file_list.end() )
        {
            file_impl * p = *m_file_iter++;
            *ppFile = p;
        }
        else
        {
            *ppFile = 0;
            nRet = 1;
        }

        return nRet;
    }

    //////////////////////////////////////////////////////////////////////////////////

    // 
    // get file size and time
    // 
    int dir_impl::get_file_size_and_time( const char * lpszFile, xos_i64 * lpSize64, xos::xos_i64 * lpCreateTime, xos::xos_i64 * lpAccessTime, xos::xos_i64 * lpModifyTime )
    {
        int nRet = 0;

        struct stat st = { 0 };

        if( 0 == nRet )
        {
            nRet = stat( lpszFile, &st );
        }

        if( ( 0 == nRet ) && lpCreateTime )
        {
            *lpCreateTime = st.st_ctime;
        }

        if( ( 0 == nRet ) && lpAccessTime )
        {
            *lpAccessTime = st.st_atime;
        }

        if( ( 0 == nRet ) && lpModifyTime )
        {
            *lpModifyTime = st.st_mtime;
        }

        if( ( 0 == nRet ) && lpSize64 )
        {
            *lpSize64 = st.st_size;
        }

        return nRet;
    }

    // 
    // 设置文件时间。linux下create time无效
    // 
    int dir_impl::set_file_time( const char * lpszFile, xos::xos_i64 cTime, xos::xos_i64 aTime, xos::xos_i64 mTime )
    {
        int ret = 0;

        struct utimbuf tm = { 0 };

        tm.actime = ( time_t )aTime;
        tm.modtime = ( time_t )mTime;

        ret = utime( lpszFile, &tm );

        return ret;
    }

    // 
    // if a file exists
    // 
    int dir_impl::is_file_exist( const char * lpszFileName )
    {
        int ret = 0;

        struct stat buf = { 0 };

        if( 0 == ret )
        {
            int r = stat( lpszFileName, &buf );
            if( -1 == r )
            {
                ret = 1;
            }
        }

        // if is file - S_ISREG
        // S_ISDIR来判断是否为目录
        if( ( 0 == ret ) && !S_ISREG( buf.st_mode ) )
        {
            ret = 1;
        }

        return ret;
    }

    // 
    // delete a file
    // 
    int dir_impl::delete_file( const char * lpszFileName )
    {
        int nRet = 0;
        nRet = remove( lpszFileName );
        return nRet;
    }

    // 
    // rename a file
    // 
    int dir_impl::rename_file( const char * lpszDesName, const char * lpszSrcName )
    {
        int nRet = 0;
        nRet = rename( lpszSrcName, lpszDesName );
        return nRet;
    }
} // xos
